<?php

/*
 * Copyright 2008 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#namespace tehframework\mvc;

#use \InvalidArgumentException;

class ActionMethodResolverImpl implements ActionMethodResolver
{
	const DEFAULT_ACTION_METHOD_NAME = 'handleRequest';
	
	const DEFAULT_PARAMETER_NAME = 'action';

	/**
	 * @var string
	 */
	private $parameterName = self::DEFAULT_PARAMETER_NAME;
	
	/**
	 * @var array
	 */
	private $methodParameterNames;
	
	/**
	 * @var array
	 */
	private $logicalMappings;
	
	/**
	 * @var string
	 */
	private $defaultMethodName = self::DEFAULT_ACTION_METHOD_NAME;
	
	/**
	 * @var string
	 */
	private $prefix;
	
	/**
	 * @var string
	 */
	private $suffix;
	
	/**
	 * @param  string $parameterName
	 * @return ActionResolverImpl
	 * @throws InvalidArgumentException
	 *         If {@link $parameterName} is empty.
	 */
	public function setParameterName($parameterName)
	{
		if (empty($parameterName))
		{
			throw new InvalidArgumentException('Parameter name cannot be empty.');
		}
		
		$this->parameterName = $parameterName;
		
		return $this;
	}
	
	/**
	 * @param  array<string> $methodParameterNames
	 * @return ActionResolverImpl
	 */
	public function setMethodParameterNames(array $methodParameterNames)
	{
		$this->methodParameterNames = $methodParameterNames;
		
		return $this;
	}
	
	/**
	 * @param  array $logicalMappings
	 * @return ActionResolverImpl
	 */
	public function setLogicalMappings(array $logicalMappings)
	{
		$this->logicalMappings = $logicalMappings;
		
		return $this;
	}
	
	/**
	 * @param  string $defaultMethodName
	 * @return ActionResolverImpl
	 * @throws InvalidArgumentException
	 *         If {@link $defaultMethodName} is empty.
	 */
	public function setDefaultMethodName($defaultMethodName)
	{
		if (empty($defaultMethodName))
		{
			throw new InvalidArgumentException('Default method name cannot be empty');
		}
		
		$this->defaultMethodName = $defaultMethodName;
		
		return $this;
	}
	
	/**
	 * @param  string $prefix
	 * @return ActionResolverImpl
	 */
	public function setPrefix($prefix)
	{
		$this->prefix = empty($prefix) ? null : $prefix;
		
		return $this;
	}
	
	/**
	 * @param  string $suffix
	 * @return ActionResolverImpl
	 */
	public function setSuffix($suffix)
	{
		$this->suffix = empty($suffix) ? null : $suffix;
		
		return $this;
	}
	
	/**
	 * @param  Request $request
	 * @return string
	 * @throws ActionMethodNotFoundException
	 */
	public function getActionMethodName( Request $request)
	{
		$methodName = null;
		
		if ($this->methodParameterNames !== null)
		{
			foreach ($this->methodParameterNames as $candidate)
			{
				if ($requestData->hasParameter($candidate))
				{
					$methodName = $candidate;
					
					break;
				}
			}
		}
		
		if (empty($methodName) && ($this->parameterName !== null))
		{
			$methodName = $request->tryGetParameter($this->parameterName);
		}
		
		if (!empty($methodName) && isset($this->logicalMappings[$methodName]))
		{
			$methodName = $this->logicalMappings[$methodName];
		}
		
		if (!empty($methodName) && !empty($this->prefix))
		{
			$methodName = $this->prefix . $this->methodName;
		}
		
		if (!empty($methodName) && !empty($this->suffix))
		{
			$methodName .= $this->suffix;
		}
		
		if (empty($methodName))
		{
			if ($this->defaultMethodName !== null)
			{
				$methodName = $this->defaultMethodName;
			}
			else
			{
				throw new ActionMethodNotFoundException($request);
			}
		}
		
		return $methodName;
	}
}